/**
 * @file scoped.jsx.
 * @author liaoxuezhi@baidu.com
 */
/* eslint fecs-indent: [0, "space", 2, 2] */

import * as React from 'react';
import {
  PureComponent,
  PropTypes
} from "react";
import {findDOMNode} from 'react-dom';
import * as assign from 'object-assign';
import * as find from 'lodash/find';

export const Enhance = ComposedComponent => class ScopedComponent extends PureComponent {

  static contextTypes = {
    scoped: PropTypes.object
  };

  static childContextTypes = {
    scoped: PropTypes.object
  };

  components = [];
  vars = {};

  static propTypes = {
    scopeRef: PropTypes.func
  };

  constructor(props, context) {
    super(props, context);

    this.registerComponent = this.registerComponent.bind(this);
    this.unRegisterComponent = this.unRegisterComponent.bind(this);
    this.getComponentByName = this.getComponentByName.bind(this);
    this.getComponents = this.getComponents.bind(this);
    this.reload = this.reload.bind(this);
    this.redirect = this.redirect.bind(this);
    this.setData = this.setData.bind(this);
    this.getData = this.getData.bind(this);
    this.receive = this.receive.bind(this);
  }

  componentWillMount() {
    const scopeRef = this.props.scopeRef;
    scopeRef && scopeRef(this);
  }


  getChildContext() {
    return {
      scoped: {
        parent: this.context.scoped,
        registerComponent: this.registerComponent,
        unRegisterComponent: this.unRegisterComponent,
        getComponentByName: this.getComponentByName,
        getComponents: this.getComponents,
        reload: this.reload,
        redirect: this.redirect,
        receive: this.receive,
        setData: this.setData,
        getData: this.getData
      }
    };
  }

  registerComponent(component) {
    if (!~this.components.indexOf(component)) {
      this.components.push(component);
    }
  }

  unRegisterComponent(component) {
    const idx = this.components.indexOf(component);

    if (~idx) {
      this.components.splice(idx, 1);
    }
  }

  getComponentByName(name) {
    const resolved = find(this.components, component => component.props.name === name);
    const parent = this.context.scoped;
    return resolved || parent && parent.getComponentByName(name);
  }

  getComponents() {
    return this.components.concat();
  }

  reload(target) {
    const scoped = this;

    if (target === 'window') {
      return location.reload();
    }

    target = typeof target === 'string' ? target.split(/\s*,\s*/) : target;
    target.forEach(name => {
      const idx = name.indexOf('.');
      let subPath = '';

      if (~idx) {
        subPath = name.substring(1 + idx);
        name = name.substring(0, idx);
      }

      const component = scoped.getComponentByName(name);

      component && component.reload && component.reload(subPath);
    });
  }

  receive(values, receive) {
    const scoped = this;
    receive = typeof receive === 'string' ? receive.split(/\s*,\s*/) : receive;
    receive.forEach(name => {
      const idx = name.indexOf('.');
      let subPath = '';

      if (~idx) {
        subPath = name.substring(1 + idx);
        name = name.substring(0, idx);
      }

      const component = scoped.getComponentByName(name);

      component && component.receive && component.receive(values, subPath);
    });
  }

  redirect() {
  }

  setData(key, value) {
    this.vars[key] = value;
  }

  getData(key, defaultValue = null) {
    return this.vars[key] || this.context.scoped && this.context.scoped.getData(key) || defaultValue;
  }

  render() {
    return (
      <ComposedComponent {...this.props} {...this.state} />
    )
  }
};

export default Enhance;